﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.MathLib
{
    public class Ellipse2d : Curve2d
    {
        public override bool IsClosed => Math.Abs(this.StartAngle - this.EndAngle) == MathUtil.DoublePi;
        public bool IsClockwise { get; set; }
        public Vector2 Center { get; set; }
        public double Rotation { get; set; }
        public double RadiusX { get; set; }
        public double RadiusY { get; set; }
        public double StartAngle { get; set; } = 0;
        public double EndAngle { get; set; } =System.Math.PI * 2;
        public Ellipse2d() 
        {
            this.Type = Curve2dType.Ellipse2d;
        }
        public override Curve2d Clone()
        {
            var result = new Ellipse2d();
            result.Copy(this);
            return result;
        }

        public override void Copy(Curve2d src)
        {
            var srcE = src as Ellipse2d;
            this.Name = srcE.Name;
            this.IsClosed = srcE.IsClosed;
            this.Source = srcE;
            this.Center = srcE.Center;
            this.Rotation = srcE.Rotation;
            this.RadiusX = srcE.RadiusX;
            this.RadiusY = srcE.RadiusY;
            this.StartAngle = srcE.StartAngle;
            this.EndAngle = srcE.EndAngle;
        }
    

        public override Curve2d Translate(Vector2 offset)
        {
            this.Center.Add(offset);
            return this;
        }

        public override Curve2d RotateAround(Vector2 basePoint, double angle)
        {
            this.Center.RotateAround(basePoint, angle); 
            return this;
        }

        public void test()
        {
            Vector2 vector2 = new Vector2(10,50);
          //  Vector2 p0 = EllipseAndEllipse.Rotate(vector2, -this.Rotation);
            Matrix3 matrix3 = Matrix3.RotateInRadian(-this.Rotation, new Vector2(0,0));
            Matrix3 matrix4 = Matrix3.RotateInRadian(-this.Rotation, this.Center);
        }
        public override Curve2d Mirror(Vector2 axisStart, Vector2 axisDir)
        {
            this.Center.Mirror(axisStart, axisDir);
            this.IsClockwise = !this.IsClockwise;
            var divAngle = axisDir.Angle();
            if (divAngle > MathUtil.Pi)
                divAngle -= MathUtil.Pi;
            this.Rotation -= 2 * (this.Rotation - divAngle);
            this.StartAngle -= 2 * (this.StartAngle - 0);
            this.EndAngle -= 2 * (this.EndAngle - 0);
            return this;
        }
        public override Vector2[] GetPoints(int div = 5,double scaleInFuture=1)
        {
            if (div <= 0)
            {
                var radius = Math.Max(this.RadiusX, this.RadiusY);
                var angle = (this.EndAngle - this.StartAngle);
                if (angle < 0)
                    angle += Utils.TwoPI;
                div = (int)Math.Ceiling(radius * scaleInFuture * Utils.TwoPI / angle*0.5);
            }
            if (div < 20)
                div = 20;
            var result = new Vector2[div+1];
            for (int i = 0; i <= div; i++)
            {
                var delta = (double)i / div;
                result[i] = Ellipse2d.getEllipsePoint(this.Center, this.RadiusX, this.RadiusY, this.StartAngle, this.EndAngle, this.Rotation, this.isClosed, delta);
            }
            return result;
        }

        public static Vector2 getEllipsePoint(Vector2 center,double radiusX,double radiusY,double startAngle,double endAngle,double rotation,bool isClockwise , double t, Vector2 optionalTarget = null)
        {
            var point = optionalTarget ?? new Vector2();
            var twoPi = MathEx.PI * 2;
            var deltaAngle = endAngle - startAngle;
            var samePoints = Math.Abs(deltaAngle) < MathEx.EPSILON;
            // ensures that deltaAngle is 0 .. 2 PI
            while (deltaAngle < 0) deltaAngle += twoPi;
            while (deltaAngle > twoPi) deltaAngle -= twoPi;
            if (deltaAngle < MathEx.EPSILON)
            {
                if (samePoints)
                {
                    deltaAngle = 0;
                }
                else
                {
                    deltaAngle = twoPi;
                }
            }
            if (isClockwise && !samePoints)
            {
                if (deltaAngle == twoPi)
                {
                    deltaAngle = -twoPi;
                }
                else
                {
                    deltaAngle = deltaAngle - twoPi;
                }
            }
            var angle = startAngle + t * deltaAngle;
            var x = center.X + radiusX * Math.Cos(angle);
            var y = center.Y + radiusY * Math.Sin(angle);
            if (rotation != 0)
            {
                var cos = Math.Cos(rotation);
                var sin = Math.Sin(rotation);
                var tx = x - center.X;
                var ty = y - center.Y;
                // Rotate the point about the center of the ellipse.
                x = tx * cos - ty * sin + center.X;
                y = tx * sin + ty * cos + center.Y;
            }
            return point.Set(x, y);
        }
    }
}
